home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIX 6.2 Applications 1996 May
/
SGI IRIX 6.2 Applications 1996 May.iso
/
dist
/
impr_dev.idb
/
usr
/
impressario
/
src
/
scan
/
file
/
scan.c.z
/
scan.c
Wrap
C/C++ Source or Header
|
1996-05-06
|
46KB
|
1,683 lines
/*
* scan.c
*
* Scanner specific module of a scanner driver for scanning from
* SGI image files. This driver supports greyscale and rgb
* versions of the SGI image file.
*
* If you are writing a scanner driver, please refer to the
* comments in the template version of scan.c for more
* information about what is going on here. Also, look in
* /usr/include/imp.h and the libimp(3) manual page for the
* interface that this module uses to deal with SGI image files.
*
* Copyright 1992, 1993 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
#include <sys/types.h>
#include <sys/times.h>
#include <sys/param.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <stdio.h>
#include <dslib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <bstring.h>
#include <signal.h>
#include <stdlib.h>
#include <invent.h>
#include <unistd.h>
#include <imp.h>
#include <locale.h>
#include <msgs/uxsgiimpr.h>
#include <scanner.h>
#include <scandrv.h>
#include "scan.h"
#include "main.h"
/*
* Stuff for converting from color images to greyscale
*/
#define RINTLUM (77)
#define GINTLUM (150)
#define BINTLUM (29)
#define ILUM(r,g,b) ((RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
#define ILUM16(r,g,b) ((RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b)))
/*
* Stuff from converting from greyscale to monochrome
*/
#define THRESH(val,thresh) ((val) > (thresh) ? 1 : 0)
#define THRESHVAL 128
/*
* Scale a pixel from 2 bytes to 1 byte
*/
#define SCALE(pixel) (((pixel * 255) / (imgMaxValue - imgMinValue)) & 0xff)
/*
* imgOffset and imgStride are global variables used in the conversion
* functions. imgOffset is the number of pixels in each row to skip
* while converting, and imgStride is the number of pixels in each row.
*
* The reason we do this is that the libimp interface gives us image
* data a row at a time, and the scan interface requires us to crop
* the scanned area. We do the cropping at the same time that we
* convert the data to a format that fits into the scan interface spec
* so that we only need to do one pass of conversion over each row.
* This all gets done in the DoImgProc thread, which calls our convert
* function for each row (see SetupScan below).
*/
static int imgOffset, imgStride;
/*
* Temporary memory for holding rows being scaled down from 16 bits to
* 8 bit.
*/
static void *imgTempBuf = NULL;
/*
* These global variables get used by the function that scales 16 bit
* per pixel data down to 8 bit pixel data.
*/
static long imgMaxValue, imgMinValue;
/*
* Pointer to a function for getting rows of data from the image file.
* We use this level of indirection to avoid having to do a
* complicated if test in DoScan; instead, we do all the testing we
* need in SetupScan and set imgGetRows appropriately.
*/
static int (*imgGetRows)(IMPImage *img, short y, short z,
void *buf, int nrows);
/*
* static int
* HowManyBits(unsigned short maxVal)
*
* Description:
* Figure out how many bits need to be used to represent maxVal
*
* Parameters:
* maxVal
*
* Returns:
* The number of bits necessary to represent maxVal
*/
static int
HowManyBits(unsigned short maxVal)
{
int i;
/*
* You still need at least a bit to represent all 0's.
*/
if (!maxVal) {
return 1;
}
i = 0;
while (maxVal) {
i++;
maxVal >>= 1;
}
return i;
}
/*
* SCANINFO *
* OpenScanner(char *dev)
*
* Description:
* Get a SCANINFO structure for the scanner connected to dev.
* This opens the device and does an inquiry to find out what
* kind of scanner is attached. If it's one we know about, we
* allocate a SCANINFO structure, fill it in, and return it.
*
* Parameters:
* dev device for the scanner
*
* Returns:
* pointer to a SCANATTRIB if successful, NULL with drverr set if
* failure.
*/
SCANINFO *
OpenScanner(char *dev)
{
static SCANINFO scan;
IMPImage *img;
static SCDATATYPE rgb8types[] = {
{ SC_PACKPLANE, 3, SC_RGB, 8 }, /* planar RGB */
{ SC_PACKPIX, 3, SC_RGB, 8 }, /* pixel packed RGB */
{ SC_PACKPIX, 1, SC_GREY, 8 }, /* 8 bit grey scale */
{ SC_PACKPIX, 1, SC_MONO, 1 }, /* 8 black and white */
};
static SCDATATYPE rgb16types[] = {
{ SC_PACKPLANE, 3, SC_RGB, 16 }, /* > 8 bit planar RGB */
{ SC_PACKPIX, 3, SC_RGB, 16 }, /* > 8 bit pixel packed RGB */
{ SC_PACKPLANE, 3, SC_RGB, 8 }, /* planar RGB */
{ SC_PACKPIX, 3, SC_RGB, 8 }, /* pixel packed RGB */
{ SC_PACKPIX, 1, SC_GREY, 16 }, /* > 8 bit grey scale */
{ SC_PACKPIX, 1, SC_GREY, 8 }, /* 8 bit grey scale */
{ SC_PACKPIX, 1, SC_MONO, 1 }, /* 8 black and white */
};
static SCDATATYPE grey8types[] = {
{ SC_PACKPIX, 1, SC_GREY, 8 }, /* 8 bit grey scale */
{ SC_PACKPIX, 1, SC_GREY, 8 }, /* 8 bit grey scale */
{ SC_PACKPIX, 1, SC_MONO, 1 }, /* 8 black and white */
};
static SCDATATYPE grey16types[] = {
{ SC_PACKPIX, 1, SC_GREY, 16 }, /* 8 bit grey scale */
{ SC_PACKPIX, 1, SC_GREY, 8 }, /* 8 bit grey scale */
{ SC_PACKPIX, 1, SC_MONO, 1 }, /* 8 black and white */
};
static float res = 100; /* set resolution somewhat */
/* arbitrarily to 100 */
static char errorBuf[SC_MAXERRSTR];
char tmpFile[MAXPATHLEN], *tmpDir;
int bits;
struct sigaction act, oact;
pid_t pid;
int fd, status;
/*
* Check for file existence before calling impOpen.
*/
if (access(dev, F_OK | R_OK) != 0) {
drverr = errno;
return NULL;
}
img = impOpen(dev, "r");
/*
* If the open failed, try using imgcopy to convert the file to
* SGI format.
*/
if (!img) {
drvmsg = impErrorString(IMPerrno);
drverr = SCEDRVMSG;
/*
* Create a temp name for use in storing the converted file
*/
tmpDir = getenv("TMPDIR");
if (!tmpDir) {
tmpDir = "/var/tmp";
}
(void)sprintf(tmpFile, "%s/fileXXXXXX", tmpDir);
(void)mktemp(tmpFile);
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaction(SIGCHLD, &act, &oact);
pid = fork();
/*
* Child runs imgcopy
*/
if (pid == 0) {
for (fd = getdtablesize(); fd > 2; fd--) {
(void)close(fd);
}
/*
* Point stderr to /dev/null to get rid of obnoxious error
* messsages on terminal
*/
(void)close(2);
(void)open("/dev/null", O_WRONLY);
(void)execlp("imgcopy", "imgcopy", "-fSGI", dev, tmpFile, NULL);
exit(-1);
}
/*
* Parent waits for child, and then tries to open the
* converted file if imgcopy exits with a 0 status
*/
if (pid > 0) {
if ((pid = waitpid(pid, &status, 0)) == pid
&& WIFEXITED(status) && WEXITSTATUS(status) == 0) {
img = impOpen(tmpFile, "r");
}
}
/*
* unlink the tmpFile so it doesn't hang around after we're
* done. We've still got it open, though, and img is our
* pointer into it.
*/
(void)unlink(tmpFile);
(void)sigaction(SIGCHLD, &oact, NULL);
if (!img) {
return NULL;
} else {
/*
* If we succeeded we have to reset drverr or an error
* will get reported.
*/
drverr = 0;
}
}
if (impNumChannels(img) < 3 && impNumChannels(img) != 1) {
(void)sprintf(errorBuf,
gettxt(_SGI_FILESCAN_BADTYPE,
"Can't figure out what type of image "
"file %s is\n"), dev);
drvmsg = errorBuf;
drverr = SCEDRVMSG;
return NULL;
}
if (impRasterBPP(img) != 1 && impRasterBPP(img) != 2) {
(void)sprintf(errorBuf,
gettxt(_SGI_FILESCAN_WEIRDBPP,
"%s has a weird number of bytes per pixel (%d)"),
dev, impRasterBPP(img));
drvmsg = errorBuf;
drverr = SCEDRVMSG;
return NULL;
}
if (impRasterBPP(img) == 2) {
bits = HowManyBits(impMaxValue(img));
imgMaxValue = impMaxValue(img);
imgMinValue = impMinValue(img);
}
/*
* If num channels is 3, it's an rgb image. If it's 1, it's a greyscale
* image. Otherwise, it's a mystery to us.
*/
if (impNumChannels(img) >= 3) {
/*
* The impMaxValue test keeps us out of a situation in which
* we give bad info to the scan app when we have a strange
* image file that uses 2 bytes per pixel but doesn't use the
* high bytes at all.
*/
if (impRasterBPP(img) == 1 || impMaxValue(img) <= 255) {
scan.types = rgb8types;
scan.ntypes = sizeof rgb8types/sizeof *rgb8types;
} else {
scan.types = rgb16types;
scan.ntypes = sizeof rgb16types/sizeof *rgb16types;
rgb16types[0].bpp = rgb16types[1].bpp = rgb16types[4].bpp = bits;
}
} else if (impNumChannels(img) == 1) {
if (impRasterBPP(img) == 1 || impMaxValue(img) <= 255) {
scan.types = grey8types;
scan.ntypes = sizeof grey8types/sizeof *grey8types;
} else {
scan.types = grey16types;
scan.ntypes = sizeof grey16types/sizeof *grey16types;
grey16types[0].bpp = bits;
}
} else {
drverr = SCENOTSUPPORTED;
return NULL;
}
/*
* This tells main.c that we only support one resolution in
* "hardware", 100. We set min and max to allow for impulse
* zooming main.c can do in cooperation with us to achieve other
* resolutions.
*/
scan.metric = SC_INCHES;
scan.nres = 1;
scan.xres = scan.yres = &res;
scan.minxres = scan.minyres = 1;
scan.maxxres = scan.maxyres = 2 * res;
scan.pagex = 0;
scan.pagey = 0;
scan.pagewidth = impXSize(img) / res;
scan.pageheight = impYSize(img) / res;
scan.priv = img;
return &scan;
}
/*
* Conversion functions.
*
* The following functions convert from the four libimp formats that
* we support (rgb and greyscale, 1 byte and 2 bytes per pixel) to the
* seven scanner interface formats that we support (planar rgb 8,
* planar rgb 16, chunky rgb 8, chunky rgb 16, greyscale 8, greyscale
* 16, and mono). (If the image file is in greyscale format, we don't
* convert to color)
*
* All conversion takes place in the DoImgProc thread using the
* "convert" member of the SCANPARAMS structure passed in to
* SetupScan. In SetupScan we set params->convert to point to the
* appropriate conversion function given the type of image file we're
* dealing with and the data type that we've been requested to provide.
*/
/*
* static void
* RGB8ToChunky8(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
*
* Description:
* Convert a row of banded 8 bit/channel RGB image data to a row
* of chunky 8 bit/channel RGB image data, cropping as necessary.
*
* Parameters:
* frombuf Banded RGB data from image file, 8 bits/pixel/channel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 8 bit/channel chunky RGB data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
RGB8ToChunky8(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
{
register unsigned char *r, *g, *b;
register unsigned char *t = tobuf;
register int x, fx;
/*
* We're cropping the data as well as converting and zooming it.
* We skip imgOffset pixels in each channel. imgStride is the
* number of pixels per channel that we actually read from the
* image file.
*/
r = (char *)frombuf + imgOffset;
g = r + imgStride;
b = g + imgStride;
/*
* The zmap test is outside the loops rather than having one loop
* with the zmap test because we want to reduce the amount of
* processing per pixel as much as possible.
*/
if (zmap) {
for (x = 0; x < tox; x++) {
fx = zmap[x];
*t++ = r[fx];
*t++ = g[fx];
*t++ = b[fx];
}
} else {
while (tox--) {
*t++ = *r++;
*t++ = *g++;
*t++ = *b++;
}
}
}
/*
* static void
* RGB16ToChunky16(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
*
* Description:
* Convert a row of banded 16 bit/channel RGB image data to a row
* of chunky 16 bit/channel RGB image data, cropping as necessary.
*
* Parameters:
* frombuf Banded RGB data from image file, 16 bits/pixel/channel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 16 bit/channel chunky RGB data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
RGB16ToChunky16(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
{
register unsigned short *r, *g, *b;
register unsigned short *t = tobuf;
register int x, fx;
/*
* We're cropping the data as well as converting and zooming it.
* We skip imgOffset pixels in each channel. imgStride is the
* number of pixels per channel that we actually read from the
* image file.
*/
r = (unsigned short *)frombuf + imgOffset;
g = r + imgStride;
b = g + imgStride;
/*
* The zmap test is outside the loops rather than having one loop
* with the zmap test because we want to reduce the amount of
* processing per pixel as much as possible.
*/
if (zmap) {
for (x = 0; x < tox; x++) {
fx = zmap[x];
*t++ = r[fx];
*t++ = g[fx];
*t++ = b[fx];
}
} else {
while (tox--) {
*t++ = *r++;
*t++ = *g++;
*t++ = *b++;
}
}
}
/*
* static void
* RGB16ToChunky8(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
*
* Description:
* Convert a row of banded 16 bit/channel RGB image data to a row
* of chunky 8 bit/channel RGB image data, cropping as necessary.
*
* Parameters:
* frombuf Banded RGB data from image file, 16 bits/pixel/channel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 8 bit/channel chunky RGB data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
RGB16ToChunky8(void *frombuf, int fromx, void *tobuf, int tox, int *zmap)
{
register unsigned short *r, *g, *b;
register unsigned char *t = tobuf;
register int x, fx;
/*
* We're cropping the data as well as converting and zooming it.
* We skip imgOffset pixels in each channel. imgStride is the
* number of pixels per channel that we actually read from the
* image file.
*/
r = (unsigned short *)frombuf + imgOffset;
g = r + imgStride;
b = g + imgStride;
/*
* The zmap test is outside the loops rather than having one loop
* with the zmap test because we want to reduce the amount of
* processing per pixel as much as possible.
*/
if (zmap) {
for (x = 0; x < tox; x++) {
fx = zmap[x];
*t++ = SCALE(r[fx]);
*t++ = SCALE(g[fx]);
*t++ = SCALE(b[fx]);
}
} else {
while (tox--) {
*t++ = SCALE(*r++);
*t++ = SCALE(*g++);
*t++ = SCALE(*b++);
}
}
}
/*
* static void
* CropRow8(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
*
* Description:
* Crop a row of image data. This function is used when scanning
* planar RGB from a color image file or when scanning greyscale
* from a greyscale image file.
*
* Parameters:
* frombuf 8 bits/channel image data
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 8 bits/channel cropped image data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
CropRow8(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
{
register char *s = (char *)fromBuf + imgOffset;
register unsigned char *t = toBuf;
register int x;
if (zmap) {
for (x = 0; x < tox; x++) {
*t++ = s[zmap[x]];
}
} else {
while (tox--) {
*t++ = *s++;
}
}
}
/*
* static void
* CropRow16(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
*
* Description:
* Crop a row of image data. This function is used when scanning
* planar RGB from a color image file or when scanning greyscale
* from a greyscale image file.
*
* Parameters:
* frombuf 16 bits/channel image data
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 16 bits/channel cropped image data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
CropRow16(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
{
register unsigned short *s = (unsigned short *)fromBuf + imgOffset;
register unsigned short *t = toBuf;
register int x;
if (zmap) {
for (x = 0; x < tox; x++) {
*t++ = s[zmap[x]];
}
} else {
while (tox--) {
*t++ = *s++;
}
}
}
/*
* static void
* CropRow16To8(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
*
* Description:
* Crop a row of image data. This function is used when scanning
* planar RGB from a color image file or when scanning greyscale
* from a greyscale image file.
*
* Parameters:
* frombuf 16 bits/channel image data
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 8 bits/channel cropped image data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
CropRow16To8(void *fromBuf, int fromx, void *toBuf, int tox, int *zmap)
{
register unsigned short *s = (unsigned short *)fromBuf + imgOffset;
register unsigned char *t = toBuf;
register int x;
if (zmap) {
for (x = 0; x < tox; x++) {
*t++ = SCALE(s[zmap[x]]);
}
} else {
while (tox--) {
*t++ = SCALE(*s++);
}
}
}
/*
* static void
* RGB8ToGrey8(void *frombuf, int fromx, void *tobuf,
* register int tox, int *zmap)
*
* Description:
* Convert a row of RGB banded data to greyscale. This involves
* adding together the illumination contributions of each of the
* red, green, and blue channels of information.
*
* Parameters:
* frombuf Banded RGB data from image file, 8 bits/pixel/channel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 8 bit greyscale data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
RGB8ToGrey8(void *frombuf, int fromx, void *tobuf,
register int tox, int *zmap)
{
register char *r, *g, *b;
register unsigned char *t = tobuf;
register int z;
r = (char *)frombuf + imgOffset;
g = r + imgStride;
b = g + imgStride;
if (zmap) {
while (tox--) {
z = *zmap++;
*t++ = ILUM(r[z], g[z], b[z]);
}
} else {
while (tox--) {
*t++ = ILUM(*r++, *g++, *b++);
}
}
}
/*
* static void
* RGB16ToGrey16(void *frombuf, int fromx, void *tobuf,
* register int tox, int *zmap)
*
* Description:
* Convert a row of RGB banded data to greyscale. This involves
* adding together the illumination contributions of each of the
* red, green, and blue channels of information.
*
* Parameters:
* frombuf Banded RGB data from image file, 16 bits/pixel/channel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 16 bit greyscale data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
RGB16ToGrey16(void *frombuf, int fromx, void *tobuf,
register int tox, int *zmap)
{
register unsigned short *r, *g, *b;
register unsigned short *t = tobuf;
register int z;
r = (unsigned short *)frombuf + imgOffset;
g = r + imgStride;
b = g + imgStride;
if (zmap) {
while (tox--) {
z = *zmap++;
*t++ = ILUM(r[z], g[z], b[z]);
}
} else {
while (tox--) {
*t++ = ILUM(*r++, *g++, *b++);
}
}
}
/*
* static void
* RGB16ToGrey8(void *frombuf, int fromx, void *tobuf,
* register int tox, int *zmap)
*
* Description:
* Convert a row of RGB banded data to greyscale. This involves
* adding together the illumination contributions of each of the
* red, green, and blue channels of information.
*
* Parameters:
* frombuf Banded RGB data from image file, 16 bits/pixel/channel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 8 bit greyscale data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
/*ARGSUSED*/
static void
RGB16ToGrey8(void *frombuf, int fromx, void *tobuf,
register int tox, int *zmap)
{
register unsigned short *r, *g, *b;
register unsigned char *t = tobuf;
register int z;
r = (unsigned short *)frombuf + imgOffset;
g = r + imgStride;
b = g + imgStride;
if (zmap) {
while (tox--) {
z = *zmap++;
*t++ = SCALE(ILUM(r[z], g[z], b[z]));
}
} else {
while (tox--) {
*t++ = SCALE(ILUM(*r++, *g++, *b++));
}
}
}
/*
* static void
* ScaleRow(void *from, void *to, register int width)
*
* Description:
* Scale row is used by functions that convert from 2 byte per
* pixel data to 1 byte per pixel data. First, the data is
* scaled, and then the appropriate conversion takes place.
*
* Parameters:
* from source row
* to destination row
* width width of row in pixels
*/
static void
ScaleRow(void *from, void *to, register int width)
{
register unsigned char *c = (unsigned char *)to + imgOffset;
register unsigned short *s = (unsigned short *)from + imgOffset;
while (width--) {
*c++ = SCALE(*s++);
}
}
/*
* static void
* ScaleRowRGB(void *from, void *to, int width)
*
* Description:
* Scale row is used by functions that convert from 2 byte per
* pixel data to 1 byte per pixel data. First, the data is
* scaled, and then the appropriate conversion takes place.
*
* Parameters:
* from source row
* to destination row
* width width of row in pixels
*/
static void
ScaleRowRGB(void *from, void *to,int width)
{
register unsigned char *c = (unsigned char *)to + imgOffset;
register unsigned short *s = (unsigned short *)from + imgOffset;
register int x = width;
while (x--) {
*c++ = SCALE(*s++);
}
x = width;
c += imgStride - width;
s += imgStride - width;
while (x--) {
*c++ = SCALE(*s++);
}
x = width;
c += imgStride - width;
s += imgStride - width;
while (x--) {
*c++ = SCALE(*s++);
}
}
/*
* static void
* RGB8ToMono(void *frombuf, int fromx,
* void *tobuf, register int tox, int *zmap)
*
* Description:
* Convert a row of RGB banded data to monochrome by calculating
* the illumination contributions of each channel and then
* thresholding the result.
*
* Parameters:
* frombuf Banded RGB data from image file, 8 bits/pixel/channel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 1 bit monochrome data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
static void
RGB8ToMono(void *frombuf, int fromx, void *tobuf, register int tox, int *zmap)
{
register char *r, *g, *b;
register unsigned char *t = tobuf;
int x, endx, shift;
r = (char *)frombuf + imgOffset;
g = r + imgStride;
b = g + imgStride;
if (fromx == tox) {
while (tox >= 8) {
*t++ = THRESH(ILUM(r[0], g[0], b[0]), THRESHVAL) << 7 |
THRESH(ILUM(r[1], g[1], b[1]), THRESHVAL) << 6 |
THRESH(ILUM(r[2], g[2], b[2]), THRESHVAL) << 5 |
THRESH(ILUM(r[3], g[3], b[3]), THRESHVAL) << 4 |
THRESH(ILUM(r[4], g[4], b[4]), THRESHVAL) << 3 |
THRESH(ILUM(r[5], g[5], b[5]), THRESHVAL) << 2 |
THRESH(ILUM(r[6], g[6], b[6]), THRESHVAL) << 1 |
THRESH(ILUM(r[7], g[7], b[7]), THRESHVAL);
tox -= 8;
r += 8;
g += 8;
b += 8;
}
*t = 0;
while (tox--) {
*t |= THRESH(ILUM(r[tox], g[tox], b[tox]), THRESHVAL) << (7 - tox);
}
} else {
register int x0, x1, x2, x3, x4, x5, x6, x7;
int endx = tox & ~7;
for (x = 0; x < endx; x += 8) {
x0 = zmap[x];
x1 = zmap[x + 1];
x2 = zmap[x + 2];
x3 = zmap[x + 3];
x4 = zmap[x + 4];
x5 = zmap[x + 5];
x6 = zmap[x + 6];
x7 = zmap[x + 7];
*t++ = THRESH(ILUM(r[x0], g[x0], b[x0]), THRESHVAL) << 7 |
THRESH(ILUM(r[x1], g[x1], b[x1]), THRESHVAL) << 6 |
THRESH(ILUM(r[x2], g[x2], b[x2]), THRESHVAL) << 5 |
THRESH(ILUM(r[x3], g[x3], b[x3]), THRESHVAL) << 4 |
THRESH(ILUM(r[x4], g[x4], b[x4]), THRESHVAL) << 3 |
THRESH(ILUM(r[x5], g[x5], b[x5]), THRESHVAL) << 2 |
THRESH(ILUM(r[x6], g[x6], b[x6]), THRESHVAL) << 1 |
THRESH(ILUM(r[x7], g[x7], b[x7]), THRESHVAL);
}
shift = 7;
*t = 0;
while (x < tox) {
*t |= THRESH(ILUM(r[zmap[x]], g[zmap[x]], b[zmap[x]]),
THRESHVAL) << shift;
x++;
shift--;
}
}
}
/*
* static void
* RGB16ToMono(void *frombuf, int fromx,
* void *tobuf, register int tox, int *zmap)
*
* Description:
* Convert a row of RGB banded data to monochrome by calculating
* the illumination contributions of each channel and then
* thresholding the result.
*
* Parameters:
* frombuf Banded RGB data from image file, 16 bits/pixel/channel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 1 bit monochrome data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
static void
RGB16ToMono(void *frombuf, int fromx, void *tobuf, register int tox, int *zmap)
{
ScaleRowRGB(frombuf, imgTempBuf, fromx);
RGB8ToMono(imgTempBuf, fromx, tobuf, tox, zmap);
}
/*
* static void
* Grey8ToMono(void *frombuf, int fromx,
* void *tobuf, register int tox, int *zmap)
*
* Description:
* Convert a row of 8 bit/pixel grey scale to a row of 1
* bit/pixel monochrome data, cropping and zooming as necessary.
*
* Parameters:
* frombuf Greyscale image data, 8 bits/pixel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 1 bit monochrome data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
static void
Grey8ToMono(void *frombuf, int fromx, void *tobuf, register int tox, int *zmap)
{
char *f = (char *)frombuf + imgOffset;
unsigned char *t = tobuf;
int x, endx, shift;
if (fromx == tox) {
while (tox >= 8) {
*t++ = THRESH(f[0], THRESHVAL) << 7 |
THRESH(f[1], THRESHVAL) << 6 |
THRESH(f[2], THRESHVAL) << 5 |
THRESH(f[3], THRESHVAL) << 4 |
THRESH(f[4], THRESHVAL) << 3 |
THRESH(f[5], THRESHVAL) << 2 |
THRESH(f[6], THRESHVAL) << 1 |
THRESH(f[7], THRESHVAL);
tox -= 8;
f += 8;
}
*t = 0;
while (tox--) {
*t |= THRESH(f[tox], THRESHVAL) << (7 - tox);
}
} else {
endx = tox & ~7;
for (x = 0; x < endx; x += 8) {
*t++ = THRESH(f[zmap[x]], THRESHVAL) << 7 |
THRESH(f[zmap[x + 1]], THRESHVAL) << 6 |
THRESH(f[zmap[x + 2]], THRESHVAL) << 5 |
THRESH(f[zmap[x + 3]], THRESHVAL) << 4 |
THRESH(f[zmap[x + 4]], THRESHVAL) << 3 |
THRESH(f[zmap[x + 5]], THRESHVAL) << 2 |
THRESH(f[zmap[x + 6]], THRESHVAL) << 1 |
THRESH(f[zmap[x + 7]], THRESHVAL);
}
shift = 7;
*t = 0;
while (x < tox) {
*t |= THRESH(f[zmap[x]], THRESHVAL) << shift;
shift--;
x++;
}
}
}
/*
* static void
* Grey16ToMono(void *frombuf, int fromx,
* void *tobuf, register int tox, int *zmap)
*
* Description:
* Convert a row of 16 bit/pixel grey scale to a row of 1
* bit/pixel monochrome data, cropping and zooming as necessary.
*
* Parameters:
* frombuf Greyscale image data, 16 bits/pixel
* fromx In theory, the width of fromx. In actuality,
* imgStride is the width of frombuf and fromx is what
* we set params->xpixels to in SetupScan to make the
* main.c module set up zmap right if we're zooming.
* tobuf 1 bit monochrome data
* tox width of tox
* zmap Zoom map for impulse zoom
*/
static void
Grey16ToMono(void *frombuf, int fromx,
void *tobuf, register int tox, int *zmap)
{
ScaleRow(frombuf, imgTempBuf, fromx);
Grey8ToMono(imgTempBuf, fromx, tobuf, tox, zmap);
}
/*
* Functions for reading the data from the image file.
*
* These four functions convert from the coordinate system used by the
* scanner interface, which has the origin in the upper left corner of
* the image area, to the coordinate system that libimage uses, which
* has the origin in the lower left corner of the image area.
*/
/*
* static int
* DoGetRows(IMPImage *img, short y, short z, void *buf, int nrows)
*
* Description:
* Get rows of image data from an SGI image file. Used for
* reading from greyscale files and also from rgb files if we're
* converting to planar.
*
* Parameters:
* img SGI image file pointer
* y y coordinate (in scanner interface coordinates)
* z z coordinage (0 == red or grey, 1 == green, 2 == blue)
* buf Buffer that the data will be read into
* nrows The number of rows to read (currently must be 1)
*
* Returns:
* 0 if successful, -1 if error
*/
/*ARGSUSED*/
static int
DoGetRows(IMPImage *img, short y, short z, void *buf, int nrows)
{
short imgy;
imgy = impYSize(img) - y - 1;
if (impReadRowB(img, buf, imgy, z) == -1) {
return -1;
}
return 0;
}
/*
* static int
* DoGetRows16(IMPImage *img, short y, short z, void *buf, int nrows)
*
* Description:
* Get rows of image data from an SGI image file. Used for
* reading from greyscale files and also from rgb files if we're
* converting to planar.
*
* Parameters:
* img SGI image file pointer
* y y coordinate (in scanner interface coordinates)
* z z coordinage (0 == red or grey, 1 == green, 2 == blue)
* buf Buffer that the data will be read into
* nrows The number of rows to read (currently must be 1)
*
* Returns:
* 0 if successful, -1 if error
*/
/*ARGSUSED*/
static int
DoGetRows16(IMPImage *img, short y, short z, void *buf, int nrows)
{
short imgy;
imgy = impYSize(img) - y - 1;
if (impReadRow(img, buf, imgy, z) == -1) {
return -1;
}
return 0;
}
/*
* static int
* DoGetRowsRGB(IMPImage *img, short y, short z, void *buf, int nrows)
*
* Description:
* Get rows of image data from an SGI rgb image file. This is
* used for reading from rgb files if we're converting to rgb
* chunky, greyscale, or monochrome. We use DoGetRows for rgb
* planar.
*
* Parameters:
* img SGI image file pointer
* y y coordinate (in scanner interface coordinates)
* z ignored in this function
* buf Buffer that the data will be read into
* nrows The number of rows to read (currently must be 1)
*
* Returns:
* 0 if successful, -1 if error
*/
/*ARGSUSED*/
static int
DoGetRowsRGB(IMPImage *img, short y, short z, void *buf, int nrows)
{
short imgy;
unsigned char *b = buf;
imgy = impYSize(img) - y - 1;
if (impReadRowB(img, b, imgy, 0) == -1) { /* red */
return -1;
}
b += impXSize(img);
if (impReadRowB(img, b, imgy, 1) == -1) { /* green */
return -1;
}
b += impXSize(img);
if (impReadRowB(img, b, imgy, 2) == -1) { /* blue */
return -1;
}
return 0;
}
/*
* static int
* DoGetRowsRGB16(IMPImage *img, short y, short z, void *buf, int nrows)
*
* Description:
* Get rows of image data from an SGI rgb image file. This is
* used for reading from rgb files if we're converting to rgb
* chunky, greyscale, or monochrome. We use DoGetRows for rgb
* planar.
*
* Parameters:
* img SGI image file pointer
* y y coordinate (in scanner interface coordinates)
* z ignored in this function
* buf Buffer that the data will be read into
* nrows The number of rows to read (currently must be 1)
*
* Returns:
* 0 if successful, -1 if error
*/
/*ARGSUSED*/
static int
DoGetRowsRGB16(IMPImage *img, short y, short z, void *buf, int nrows)
{
short imgy;
short *b = buf;
imgy = impYSize(img) - y - 1;
if (impReadRow(img, b, imgy, 0) == -1) { /* red */
return -1;
}
b += impXSize(img);
if (impReadRow(img, b, imgy, 1) == -1) { /* green */
return -1;
}
b += impXSize(img);
if (impReadRow(img, b, imgy, 2) == -1) { /* blue */
return -1;
}
return 0;
}
/*
* int
* SetupScan(SCANPARAMS *params)
*
* Description:
* Get ready to perform a scan. params is a value result
* parameter; it has fields that describe the scanning parameters
* desired by the scanning application, and fields that this
* function is responsible for setting.
*
* Parameters:
* params scanning parameters (in/out)
*
* Returns:
* 0 if successful, -1 with drverr set if error
*/
int
SetupScan(SCANPARAMS *params)
{
IMPImage *img = params->s->priv;
/*
* xres and yres will always be 100, because we told main.c that
* that is the only resolution we can do in "hardware". main.c
* will set up a zoom map for us later if any zooming needs to
* occur.
*/
params->xpixels = params->width * params->xres;
params->ylines = params->height * params->yres;
if (impRasterBPP(img) == 1) {
if (impNumChannels(img) >= 3) {
/*
* Set xbytes, convert, and imgGetRows appropriately for rgb
* image files.
*/
switch (params->type.type) {
case SC_RGB:
if (params->type.packing == SC_PACKPLANE) {
params->xbytes = impXSize(img);
params->convert = CropRow8;
imgGetRows = DoGetRows;
} else {
params->xbytes = impXSize(img) * 3;
params->convert = RGB8ToChunky8;
imgGetRows = DoGetRowsRGB;
}
break;
case SC_GREY:
params->xbytes = impXSize(img) * 3;
params->convert = RGB8ToGrey8;
imgGetRows = DoGetRowsRGB;
break;
case SC_MONO:
params->xbytes = impXSize(img) * 3;
params->convert = RGB8ToMono;
imgGetRows = DoGetRowsRGB;
break;
default:
drverr = SCEBADTYPE;
return -1;
}
} else {
/*
* Set xbytes, convert, and imgGetRows appropriately for
* greyscale image files.
*/
params->xbytes = impXSize(img);
params->convert = params->type.type == SC_GREY ?
CropRow8 : Grey8ToMono;
imgGetRows = DoGetRows;
}
} else {
if (impNumChannels(img) >= 3) {
switch (params->type.type) {
case SC_RGB:
if (params->type.packing == SC_PACKPLANE) {
params->xbytes = impXSize(img) * sizeof (unsigned short);
imgGetRows = DoGetRows16;
params->convert = params->type.bpp > 8 ?
CropRow16 : CropRow16To8;
} else {
params->xbytes =
impXSize(img) * 3 * sizeof (unsigned short);
imgGetRows = DoGetRowsRGB16;
params->convert = params->type.bpp > 8 ?
RGB16ToChunky16 : RGB16ToChunky8;
}
break;
case SC_GREY:
params->xbytes = impXSize(img) * 3 * sizeof (unsigned short);
imgGetRows = DoGetRowsRGB16;
params->convert = params->type.bpp > 8 ?
RGB16ToGrey16 : RGB16ToGrey8;
break;
case SC_MONO:
params->xbytes = impXSize(img) * 3 * sizeof (unsigned short);
imgGetRows = DoGetRowsRGB16;
params->convert = RGB16ToMono;
if (imgTempBuf) {
free(imgTempBuf);
}
imgTempBuf = malloc(impXSize(img) * 3);
break;
}
} else {
params->xbytes = impXSize(img) * sizeof (unsigned short);
imgGetRows = DoGetRows16;
if (params->type.type == SC_GREY) {
params->convert = params->type.bpp > 8 ?
CropRow16 : CropRow16To8;
} else {
params->convert = Grey16ToMono;
if (imgTempBuf) {
free(imgTempBuf);
}
imgTempBuf = malloc(impXSize(img));
}
}
}
/*
* Set readlines = 1 because at this point that's the only number
* of lines that DoGetRows and DoGetRowsRGB supports. If those
* two functions were expanded to do more, than this could be set
* higher and everything should work (DoScan already does the
* right thing).
*/
params->readlines = 1;
imgOffset = params->x * params->xres;
imgStride = impXSize(img);
return 0;
}
/*
* int
* ScanReset(SCANINFO *scan)
*
* Description:
* Reset the scanner to its ready state. This is called after a
* scan has been aborted. We don't have to do anything here.
*
* Parameters:
* scan Describes the scanner to reset
*
* Returns:
* 0 if successful, -1 with drverr set if error
*/
/*ARGSUSED*/
int
ScanReset(SCANINFO *scan)
{
return 0;
}
/*
* void
* DoScan(SCANPARAMS *params)
*
* Description:
* Perform a scan. We read the data from the scanner and put it on the
* scan queue so that the image processing process can get it. This
* function exits when it's done; it's meant to be called via sproc().
*
* Parameters:
* params parameters for the scan
*/
void
DoScan(SCANPARAMS *params)
{
SCANINFO *s = params->s;
IMPImage *img = s->priv;
void *buf;
int toread, curline;
int imgy, y, z;
int npasses;
/*
* Exit if our parent dies
*/
prctl(PR_TERMCHILD);
y = params->y * params->yres;
npasses = params->type.type == SC_RGB &&
params->type.packing == SC_PACKPLANE ? 3 : 1;
for (z = 0; z < npasses; z++) {
for (curline = 0; curline < params->ylines;
curline += params->readlines) {
toread = MIN(params->readlines,
params->ylines - curline);
imgy = y + curline;
buf = SCDequeue(params->sfreeq);
/*
* Get the scan data here!
*/
if ((*imgGetRows)(img, imgy, z, buf, params->readlines) < 0) {
drverr = SCEDRVMSG;
drvmsg = impErrorString(IMPerrno);
exit(1);
}
/*
* Chop the buffer up into scan line sized chunks
*/
while (toread--) {
SCEnqueue(params->scanq, buf);
buf = (char *)buf + params->xbytes;
}
}
}
exit(0);
}
/*
* These feeder functions should never get called, since we have
* denied having a feeder by not setting the feederFlags member of the
* SCANINFO struct in OpenScanner. See the scanner driver template
* version of scan.c for comments on what these functions should do if
* there really is a feeder attached.
*/
/*ARGSUSED*/
int
SetFeederFlags(SCANINFO *scan, SCFEEDERFLAGS flags)
{
drverr = SCENOFEEDER;
return -1;
}
/*ARGSUSED*/
int
AdvanceFeeder(SCANINFO *scan)
{
drverr = SCENOFEEDER;
return -1;
}
/*ARGSUSED*/
int
FeederReady(SCANINFO *scan)
{
drverr = SCENOFEEDER;
return -1;
}
/*
* void
* PrintID(FILE *fp)
*
* Description:
* Print a string to fp that describes the type of scanner that
* this driver supports.
*
* Parameters:
* fp stream upon which to print scanner id string
*/
void
PrintID(FILE *fp)
{
fprintf(fp, "SGI Image File\n"); /* String describing scanner */
fprintf(fp, "Other"); /* Device type; can be list */
}
/*
* void
* FindScanners(FILE *fp)
*
* Description:
* Look for scanners that this driver can support. Since this
* isn't really feasible for SGI image files, we just print
* nothing.
*
* Parameters:
* fp stream upon which to print stuff
*/
/*ARGSUSED*/
void
FindScanners(FILE *fp)
{
}
/*
* int
* InstallScanner(char *dev)
*
* Description:
* This function gets called to implement the "-install" option
* of the driver. The scanner installation tool wants to install
* a scanner with us as the driver and dev as the device.
*
* In our case, "dev" is supposedly an image file. We make sure
* that we can read it, that iopen can open it, and that it's an
* image file that we understand.
*
* Parameters:
* dev Device to use to install scanner
*
* Returns:
* 0 if successful, -1 if error.
*/
int
InstallScanner(char *dev)
{
IMPImage *img;
SCANINFO *scan;
if (access(dev, F_OK | R_OK) != 0) {
printf(gettxt(_SGI_FILESCAN_CANTACCESS,
"Can't open %s for reading: %s\n"),
dev, strerror(errno));
return -1;
}
scan = OpenScanner(dev);
if (!scan) {
printf("%s\n", drverr == SCEDRVMSG ? drvmsg : SCErrorString(drverr));
}
return 0;
}
/*
* int
* DeleteScanner(char *dev)
*
* Description:
* This function gives the scanner driver the opportunity to
* deallocate any resources allocated during InstallScanner, and
* to do any scanner-specific cleanup necessary for deleting a
* scanner.
*
* Parameters:
* dev Device of scanner being deleted
*
* Returns:
* 0 if successful, -1 if error.
*/
/*ARGSUSED*/
int
DeleteScanner(char *dev)
{
return 0;
}
/*
* void *
* GetSaveOptions(SCANINFO *scan, int *nBytes)
*
* Description:
* This function should return to the main.c module a pointer to
* some bytes representing our current settings that we got from
* our scanner specific options program. If we don't have a
* scanner specific options program, we just set drverr and
* return NULL.
*
* The reason for doing this is so that the scanner application
* can save some state for us, and at a later time give us the
* same bytes back so that we can make our state match what it
* was before.
*
* Parameters:
* scan SCANINFO
* nBytes we fill this in with the number of bytes we're returning
*
* Returns:
* pointer to bytes containing scanner specific options settings
* if successful, NULL if error. drverr must be set to an
* appropriate error code from <scanner.h> or <sys/errno.h> if an
* error occurs.
*/
void *
GetSaveOptions(SCANINFO *scan, int *nBytes)
{
drverr = SCENOSAVEOPT;
return NULL;
}
/*
* int
* SetSaveOptions(SCANINFO *scan, void *options, int nBytes)
*
* Description:
* In this function, the scanner application is restoring state
* that it previously saved after calling GetSaveOptions. We
* should reset our state to reflect the options passed to us.
*
* These are scanner specific settings that were set by our
* scanner specific options program; we don't need to worry about
* things like resolution and scanning area and data type that
* are a part of the standard scanning protocol here.
*
* Parameters:
* scan SCANINFO
* options the saved settings
* nBytes number of bytes pointed to by options
*
* Returns:
* 0 if successful, -1 if error. drverr must be set to an
* appropriate error code from <scanner.h> or <sys/errno.h> if an
* error occurs.
*/
int
SetSaveOptions(SCANINFO *scan, void *options, int nBytes)
{
drverr = SCENOSAVEOPT;
return -1;
}